import re

from moviepy.editor import *
from moviepy.video.tools.subtitles import SubtitlesClip

from common.common_tools import get_str_parts
from common.global_config import SUBTITLE_CONF


def melt_concatenate_videoclips(clips, durations=[], method="chain", transition=None,
                                bg_color=None, ismask=False, padding=0):
    new_clips = []
    image_duration = 0.3
    if clips and len(clips) > 1:
        pre_tail_clip_temp = None
        for i, clip in enumerate(clips):
            header_duration = 0
            tail_duration = 0
            if durations:
                if len(durations) > i:
                    tail_duration = durations[i]
                if i > 0 and len(durations) > i - 1:
                    header_duration = durations[i - 1]
            main_clip = clip
            if header_duration > 0 and pre_tail_clip_temp:
                pre_tail_clip_temp = pre_tail_clip_temp.set_duration(image_duration).set_opacity(0.2).crossfadeout(
                    image_duration)
                main_clip = main_clip.crossfadein(min(main_clip.duration, header_duration))
                main_clip = CompositeVideoClip([pre_tail_clip_temp, main_clip])
                pre_tail_clip_temp = None
            new_clips.append(main_clip)
            if tail_duration > 0:
                tail_image_clip = clip.to_ImageClip(clip.duration)
                pre_tail_clip_temp = tail_image_clip
    else:
        new_clips = clips
    return concatenate_videoclips(new_clips, method, transition, bg_color, ismask, padding)


def add_subtitles(videoClip, text):
    if not text:
        return videoClip
    separators = SUBTITLE_CONF["separators"]
    max_lines = SUBTITLE_CONF["max_lines"]
    max_line_num = SUBTITLE_CONF["max_line_num"]
    videoClip.set_ismask(True)
    total_duration = videoClip.duration
    bg_clip = ColorClip(SUBTITLE_CONF["size"], color=(0, 0, 0)).set_duration(total_duration)
    data = []
    total_length = len(text)
    current_start = 0
    current_lines = []
    for line in text.splitlines():
        if not line:
            continue
        str_parts = get_str_parts(line, separators, max_line_num)
        current_lines.extend(str_parts)
        while len(current_lines) >= max_lines:
            (current_start, current_end), line = __get_one_subtitle(current_lines[:max_lines], current_start,
                                                                    total_duration,
                                                                    total_length)
            data.append(((current_start, current_end), line))
            current_lines = current_lines[max_lines:]
            current_start = current_end
    if current_lines:
        (current_start, current_end), line = __get_one_subtitle(current_lines, current_start,
                                                                total_duration,
                                                                total_length)
        data.append(((current_start, current_end), line))
    generator = lambda txt: TextClip(txt, font=SUBTITLE_CONF["font"], fontsize=SUBTITLE_CONF["fontsize"],
                                     color=SUBTITLE_CONF["color"])
    subtitle_clips = SubtitlesClip(data, generator)
    final_clip = CompositeVideoClip(
        [bg_clip, videoClip, subtitle_clips.set_position(("center", videoClip.h + 5))])
    return final_clip


def __get_one_subtitle(current_lines, current_start, total_duration, total_length):
    line = "\n".join(current_lines)
    line_duration = total_duration * len(line) / total_length
    final_line = line.rstrip(SUBTITLE_CONF["separators"])
    # 去除spare_chars字符
    final_line = re.sub('[' + SUBTITLE_CONF["spare_chars"] + ']', '', final_line)
    return (current_start, current_start + line_duration), final_line


def animation_and(clip, animations, bg_size=None):
    clip_start_time = clip.start
    clip = clip.set_start(0)
    addition_list = []
    has_move = False
    for animation in animations:
        in_start = animation.get("start")
        duration = animation.get("duration")
        func = animation.get("func")
        if func.find("move_") > -1:
            has_move = True
        in_start += clip_start_time
        addition = clip.to_ImageClip(t=in_start).set_duration(duration).set_position(clip.pos)
        addition = eval("addition.%s" % func)
        addition_list.append(((in_start, in_start + duration), addition))
    min_ta = min([ta for (ta, tb), addition in addition_list])
    max_tb = max([tb for (ta, tb), addition in addition_list])
    before = clip.subclip(0, min_ta)
    pre_tb = None
    final_all_list = []
    final_all_list.append(before)
    for (ta, tb), addition in addition_list:
        final_all_list.append(addition)
        if pre_tb and pre_tb < ta:
            final_all_list.append(clip.subclip(pre_tb, ta))
        pre_tb = tb
    if max_tb < clip.duration:
        after = clip.subclip(max_tb)
        final_all_list.append(after)
    if has_move:
        final_all_list = [CompositeVideoClip([c], size=bg_size) for c in final_all_list]
    final = concatenate_videoclips(final_all_list).set_start(clip_start_time)
    return final
